-- object

function new(trait)
  local object = {
    __traits = {},
    __ref_count = {},
    __explicit_applied = {},
  }
  if trait ~= nil then
    apply(object, trait)
  end
  return object
end

function clone(prototype)
  local new = {}
  for k, v in pairs(prototype) do
    if type(v) == 'table' then
      v = clone(v)
    end
    new[k] = v
  end
  return new
end

-- trait

local _global_traits = {} 
function trait(name, definition)
  _global_traits[name] = definition
end

function apply(object, trait, ...)
  if _global_traits[trait] == nil then
    error('trait not fount: ' .. trait)
  end
  local object_t = object.__traits
  local object_ea = object.__explicit_applied
  if object_t[trait] == nil or object_ea[trait] == nil then --未apply的trait，或者隐式apply的trait才继续
    object_ea[trait] = 
      (object_ea[trait] or 0) + 1
    _apply_trait(object, trait, ...)
  end
end

function _apply_trait(object, trait_name, ...)
  local definition = _global_traits[trait_name]

  local object_rc = object.__ref_count
  object_rc[trait_name] = 
    (object_rc[trait_name] or 0) + 1

  local need = definition.need
  if need ~= nil then
    for i = 1, #need do
      _apply_trait(object, need[i])
    end
  end
  local object_t = object.__traits
  -- 如果trait未apply则apply之，隐式apply的trait不重复初始化
  if object_t[trait_name] == nil then
    object_t[trait_name] = definition
    if definition.attribute ~= nil then
      for attr_name, attr_value in pairs(definition.attribute) do
        object[attr_name] = attr_value
      end
    end
    if definition.apply ~= nil then --类似构造函数
      definition.apply(object, ...)
    end
  end
end

function remove(object, trait)
  if object.__traits[trait] == nil then
    return
  end
  local object_ea = object.__explicit_applied
  if object_ea[trait] ~= nil and object_ea[trait] > 0 then --显式apply的trait才允许remove
    _remove_trait(object, trait)
    object_ea[trait] = object_ea[trait] - 1
    if object_ea[trait] == 0 then
      object_ea[trait] = nil
    end
  end
end

function _remove_trait(object, trait)
  local definition = object.__traits[trait]

  object.__ref_count[trait] = object.__ref_count[trait] - 1
  if object.__ref_count[trait] == 0 then
    object.__ref_count[trait] = nil
    if definition.need ~= nil then
      for i = 1, #definition.need do
        _remove_trait(object, definition.need[i])
      end
    end
    if definition.attribute ~= nil then
      for attr_name, _ in pairs(definition.attribute) do
        object[attr_name] = nil
      end
    end
    object.__traits[trait] = nil
  end
end

-- message

function send(target, namespace, message, ...)
  if namespace == nil then -- 如果不指定namespace，则会遍历所有namespace，且所有函数都会被调用
    for trait_name, definition in pairs(target.__traits) do
      if definition.provide ~= nil and definition.provide[message] ~= nil then
        definition.provide[message](target, ...)
      end
    end
  else
    if target.__traits[namespace].provide ~= nil and target.__traits[namespace].provide[message] ~= nil then
      target.__traits[namespace].provide[message](target, ...)
    end
  end
end

function broadcast(targets, namespace, message, ...)
end

-- coroutine

function set_coroutine(object, func)
end

function run_coroutine()
end
